#include <ArduinoJson.h>
#include "AtConfig.h"

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

//制造重启命令
void(* resetFunc) (void) = 0; 

#include "HttpUpdate.h"
#include "Switch.h"
#include "Code.h"

// wifi and mqtt
WiFiClient espClient;
PubSubClient client(espClient);
#define MSG_BUFFER_SIZE (1024)

const char* version = "1.0.0";

int cnt = 0;
long last = 0;
int ledStatus = LOW;

//Switch
Switch sw;

// eeprom config
AtConfig atconf;
BaseConf conf;

// wifi connect
void wifi_setup()
{

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(conf.wifi_ssid);

  WiFi.begin(conf.wifi_ssid, conf.wifi_password);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

// mqtt发送固定格式消息
void mqtt_send_msg(int code, const char* msg) {
  char payload[MSG_BUFFER_SIZE];
  snprintf(payload, MSG_BUFFER_SIZE, "{\"aswcode\":\"%d\",\"aswmsg\":\"%s\"}", code, msg);
  client.publish(conf.mqtt_pub, payload);
  Serial.printf("Message send [%s] %s\r\n", conf.mqtt_pub, payload);
}

void mqtt_send_msg(int code, char* msg) {
  char payload[MSG_BUFFER_SIZE];
  snprintf(payload, MSG_BUFFER_SIZE, "{\"aswcode\":\"%d\",\"aswmsg\":\"%s\"}", code, msg);
  client.publish(conf.mqtt_pub, payload);
  Serial.printf("Message send [%s] %s\r\n", conf.mqtt_pub, payload);
}

void mqtt_send_msg(int code, int msg) {
  char payload[MSG_BUFFER_SIZE];
  snprintf(payload, MSG_BUFFER_SIZE, "{\"aswcode\":\"%d\",\"aswmsg\":\"%d\"}", code, msg);
  client.publish(conf.mqtt_pub, payload);
  Serial.printf("Message send [%s] %s\r\n", conf.mqtt_pub, payload);
}

void mqtt_send_config(int code, const char* msg) {
  char payload[MSG_BUFFER_SIZE];
  snprintf(payload, MSG_BUFFER_SIZE, "{\"aswcode\":\"%d\",\"aswmsg\":%s}", code, msg);
  client.publish(conf.mqtt_pub, payload);
  Serial.printf("Message send [%s] %s\r\n", conf.mqtt_pub, payload);
}

// mqtt callback
void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++)
  {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  StaticJsonDocument<1024> doc;
  DeserializationError error = deserializeJson(doc, payload);
  if (error)
  {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return;
  }
  // const char *code = doc["code"];
  // const char *msg = doc["msg"];
  String code_str = doc["code"];
  String msg_str = doc["msg"];
  int code = code_str.toInt();

  switch (code)
  {
  case CODE_SWITCH_SET_CONFIG:
    atconf.setConf(msg_str);
    mqtt_send_msg(CODE_SWITCH_SET_CONFIG, 1);
    break;
  case CODE_SWITCH_GET_CONFIG:
    mqtt_send_config(CODE_SWITCH_GET_CONFIG, atconf.getConf().c_str());
    break;
  case CODE_SWITCH_SET_REBOOT:
    mqtt_send_msg(CODE_SWITCH_SET_REBOOT, 1);
    delay(1000);    //延迟时间
    resetFunc();    //重启程序开始
    break;
  case CODE_SWITCH_SET_UPDATE:
    // 开始升级
    update_flag = true;
    // 清空并重新拼接升级地址
    memset(update_url, 0, sizeof(update_url));
    strlcpy(update_url, doc["msg"], sizeof(update_url));
    Serial.printf("update_url: %s", update_url);
    mqtt_send_msg(CODE_SWITCH_SET_UPDATE, 1);
    break;
  case CODE_SWITCH_GET_VERSION:
    mqtt_send_msg(CODE_SWITCH_GET_VERSION, version);
    break;
  case CODE_SWITCH_GET_SWITCH:
    mqtt_send_msg(CODE_SWITCH_GET_SWITCH, sw.getValue());
    break;
  case CODE_SYSTEM_SWITCH_OPEN:
    sw.open();
    break;
  case CODE_SYSTEM_SWITCH_CLOSE:
    sw.close();
    break;
  case CODE_SWITCH_SET_OPEN:
    sw.open();
    break;
  case CODE_SWITCH_SET_CLOSE:
    sw.close();
    break;

  default:
    break;
  }
}

void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    // String clientId = "ESP8266Client-";
    // clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(conf.mqtt_clientid, conf.mqtt_user, conf.mqtt_password))
    {
      Serial.println("connected");
      // Once connected, publish an announcement...
      mqtt_send_msg(CODE_SWITCH_GET_VERSION, version);
      mqtt_send_msg(CODE_SWITCH_GET_SWITCH, sw.getValue());
      // ... and resubscribe
      client.subscribe(conf.mqtt_sub);
      //client.subscribe(conf.mqtt_sub_sys);
    }
    else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

// 开关回调函数
void sw_callback(unsigned int status)
{
  // 上传信息
  switch (status)
  {
  case SWITCH_OPEN:
    Serial.println("open");
    mqtt_send_msg(CODE_SWITCH_GET_SWITCH, SWITCH_OPEN);
    break;

  case SWITCH_CLOSE:
    Serial.println("close");
    mqtt_send_msg(CODE_SWITCH_GET_SWITCH, SWITCH_CLOSE);
    break;

  default:
    break;
  }
}

void setup()
{
  pinMode(BUILTIN_LED, OUTPUT);

  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.println();

  atconf.setup();
  atconf.waitAtCommand();
  atconf.readConf(&conf);

  sw.setup();
  sw.setCallback(sw_callback);

  wifi_setup();
  client.setBufferSize(1024);
  client.setServer(conf.mqtt_server, conf.mqtt_port);
  client.setCallback(callback);

  update_setup();
}

void loop()
{
  if (update_flag) {
    update_run(espClient, update_url);
  }
  else {
    if (!client.connected()) {
      reconnect();
    }
    client.loop();
  }

  // sw.loop();

  // 10ms计数一次 , 系统运行指示灯
  long now = millis();
  if (now - last > 10)
  {
    last = now;
    cnt += 1;
    if (sw.getValue() == SWITCH_OPEN)
    {
      if (cnt % 10 == 0)
      {
        ledStatus = !ledStatus;
        digitalWrite(BUILTIN_LED, ledStatus);
      }
    }
    else{
      if (cnt % 100 == 0)
      {
        ledStatus = !ledStatus;
        digitalWrite(BUILTIN_LED, ledStatus);
      }
    }
  }
}
